package cn.powertime.evaluation.web.controller;

import cn.powertime.evaluation.Constants;
import cn.powertime.evaluation.entity.SysFile;
import cn.powertime.evaluation.exception.FileServerException;
import cn.powertime.evaluation.facade.SysFileFacade;
import cn.powertime.evaluation.file.storage.FileInfo;
import cn.powertime.evaluation.file.storage.FileStorage;
import cn.powertime.evaluation.service.SysFileService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 *
 * </p>
 *
 * @author ZYW
 * @version v1.0.0
 * @date 2019-08-22 18:13
 */
@RestController
@RequestMapping("/file")
@Api(value = "/file", tags = "文件操作", produces = MediaType.ALL_VALUE)
public class FileController extends BaseController {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class);

    private static final Pattern PATTERN = Pattern.compile("bytes=(\\d*)-(\\d*)");

    @Autowired
    private SysFileFacade fileFacade;

    @Autowired
    private FileStorage fileStorage;

    @Autowired
    private SysFileService sysFileService;

    @PostMapping(value = "/upload")
    @ApiOperation(value = "上传文件", notes = "上传文件")
    public Object upload(@RequestParam(value = "file", required = false) MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return error("上传文件的大小为空！");
        }
        if (Objects.requireNonNull(file.getOriginalFilename()).length() >= 50) {
            return error("上传文件名称过长，长度应小于50个字符！");
        }

        FileInfo fileInfo = fileStorage.write(file);
        Map<String, String> result = fileFacade.save(fileInfo);

        if(result != null) {
            return success(result);
        }

        return error("上传失败！");
    }

    @GetMapping("/download/{id}")
    @ApiOperation(value = "文件下载", notes = "下载上传的文件")
    public void downLoadFile(@PathVariable("id") String id, HttpServletResponse response) {
        if (StringUtils.isEmpty(id)) {
            throw new FileServerException("文件ID为空！");
        }

        SysFile sysFile = fileFacade.getById(id);
        if (sysFile == null) {
            throw new FileServerException(id + "不能查询到文件信息！");
        }

        fileStorage.read(sysFile,response);
    }

    @GetMapping("/video/{id}")
    @ApiOperation(value = "视频播放", notes = "视频播放")
    public void videoFile(@PathVariable("id") String id, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(id)) {
            throw new FileServerException("文件ID为空！");
        }
        String fileId = id;

        if (fileId.contains(Constants.DOT)) {
            fileId = Splitter.on(Constants.DOT).splitToList(fileId).get(0);
        }

        SysFile sysFile = fileFacade.getById(fileId);
        if (sysFile == null) {
            throw new FileServerException(id + "不能查询到文件信息！");
        }

        final String fileName = sysFile.getName();
        final String filePath = sysFile.getPath();
        if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(filePath)) {
            throw new FileServerException("文件路径或者名称为空！");
        }

        String downloadPath = filePath + File.separator + fileName;
        String origName = FilenameUtils.getName(filePath);
        String rangeHeader = request.getHeader("Range");

        if (StringUtils.isEmpty(rangeHeader)) {
            download(response, downloadPath, origName);
        } else {
            try {
                File file = new File(downloadPath);

                if (!file.exists()) {
                    throw new FileServerException(downloadPath + "文件不存在！");
                }
                long length = file.length();


                // 设置response参数，可以打开下载页面
                response.reset();
                response.setContentType("video/mp4");
                response.setHeader("Accept-Ranges", "bytes");
                response.setHeader("Content-Length", String.valueOf(length));

                Matcher matcher = PATTERN.matcher(rangeHeader);
                String start = "";
                String end = "";
                if (matcher.find()) {
                    start = matcher.group(1);
                    end = matcher.group(2);
                }

                Map<String, Long> range = ImmutableMap.of("start"
                        , (StringUtils.isEmpty(start) ? 0 : Long.valueOf(start))
                        , "end"
                        , StringUtils.isEmpty(end) ? (length - 1) : Long.valueOf(end));

                if (StringUtils.isEmpty(start) && StringUtils.isNotEmpty(end)) {
                    range.put("start", length - range.get("end"));
                    range.put("end", (length - 1));
                }

                if (range.get("start") >= length || range.get("end") >= length) {
                    response.setHeader("Content-Range", "bytes */" + length);
                    response.setStatus(416);
                    response.flushBuffer();
                    return;
                }

                byte[] bytes = new byte[Long.valueOf(range.get("end") - range.get("start") + 1).intValue()];
                RandomAccessFile raf = new RandomAccessFile(file, "r");
                raf.seek(range.get("start"));
                raf.read(bytes, 0, bytes.length);
                response.setHeader("Content-Length", String.valueOf(bytes.length));
                response.setHeader("Content-Range", "bytes " + range.get("start") + "-" + range.get("end") + "/" + length);
                response.setStatus(206);
                response.getOutputStream().write(bytes);
                response.flushBuffer();
                raf.close();
            } catch (Exception e) {
                //throw new FileServerException("视频播放异常！", e);
            }
        }
    }

    private void download(HttpServletResponse response, String downloadPath, String origName) {
        try {
            // 设置response参数，可以打开下载页面
            response.reset();
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            String filename = URLEncoder.encode(origName, "UTF-8");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
            File file = new File(downloadPath);
            if (!file.exists()) {
                throw new FileServerException(downloadPath + "文件不存在！");
            }
            Files.copy(file.toPath(), response.getOutputStream());
        } catch (IOException e) {
            throw new FileServerException("下载文件异常！", e);
        }
    }

    @Autowired
    SysFileFacade sysFileFacade;

    @PostMapping("/batchDel/{fileId}")
    public  Object batchDel(@PathVariable String fileId){

        boolean bl = sysFileFacade.trueDeletion(fileId);

        QueryWrapper<SysFile> chapterWrapper = new QueryWrapper<>();
        chapterWrapper.in("id", fileId);
        boolean f=sysFileService.remove(chapterWrapper);
        if (f){
            return success("删除成功");
        }
        return error("删除失败");
    }

}
